using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net.Sockets;

namespace FlexLib
{
	public class SocketReader
	{
		private Socket _socket;
		private byte[] receiveBuffer;
		private byte[] internalBuffer;

		private const int MAX_RECEIVE_BUFFER_LENGTH = 4194304;

		private void RecvBytes(int count)
		{
			while (internalBuffer.Length < count)
			{
				int recvCount = _socket.Receive(receiveBuffer);
				int oldLength = internalBuffer.Length;
				Array.Resize<byte>(ref internalBuffer, oldLength + recvCount);
				Array.Copy(receiveBuffer, 0, internalBuffer, oldLength, recvCount);
			}
		}

		private void CropInternalBuffer(int count)
		{
			byte[] newInternalBuffer = new byte[internalBuffer.Length - count];
			Array.Copy(internalBuffer, count, newInternalBuffer, 0, newInternalBuffer.Length);
			internalBuffer = newInternalBuffer;
		}

		public SocketReader(Socket socket)
		{
			_socket = socket;
			receiveBuffer = new byte[MAX_RECEIVE_BUFFER_LENGTH];
			internalBuffer = new byte[0];
		}

		public byte[] ReadBytes(int count)
		{
			byte[] buffer = new byte[count];
			RecvBytes(count);
			Array.Copy(internalBuffer, buffer, count);
			CropInternalBuffer(count);
			return buffer;
		}

		public int ReadInt()
		{
			RecvBytes(sizeof(int));

			MemoryStream ms = new MemoryStream(internalBuffer);
			BinaryReader reader = new BinaryReader(ms);
			int result = reader.ReadInt32();
			reader.Close();

			CropInternalBuffer(sizeof(int));

			return result;
		}

		public string ReadString()
		{
			int length = ReadInt();
			RecvBytes(length);
			string result = Encoding.UTF8.GetString(internalBuffer, 0, length);

			CropInternalBuffer(length);

			return result;
		}

		public void Close()
		{
			_socket.Shutdown(SocketShutdown.Both);
			_socket.Close();
		}
	}
}
